<?php
namespace lib\wechat;

/**
 * 服务器通信
 * @Auth: JH <hu@lunaz.cn>
 * Class Server
 * @package lib\wechat
 */
class Server extends Base
{


    private $appId;
    private $appSecret;
    private $token;
    private $encodingAesKey;
    private $typeEncrypt;
    protected $msgData;
    private $listens;


    /**
     * @param array $options
     * @param string $access_token
     */
    function __construct( array $options = array(), $access_token = '' )
    {
        if ($access_token) {
            parent::$accessToken = $access_token;
        }
        if ($options) {
            parent::$config = $options;
        }
        $this->token = isset( parent::$config['token'] ) ? parent::$config['token'] : '';
        $this->encodingAesKey = isset( parent::$config['encodingAesKey'] ) ? parent::$config['encodingAesKey'] : '';
        $this->appId = isset( parent::$config['appId'] ) ? parent::$config['appId'] : '';
        $this->appSecret = isset( parent::$config['appSecret'] ) ? parent::$config['appSecret'] : '';
        $this->typeEncrypt = isset( $_GET['encrypt_type'] ) ? $_GET['encrypt_type'] : '';
        parent::__construct();

        $this->getData();
    }

    function on( $name, $func )
    {
        if (!is_callable( $func )) {
            throw new Exception( "{$func} 不是一个可回调函数" );
        }
        $this->listens[$name] = $func;
        return $this;
    }

    function run()
    {
        if ($callable = array_keys( $this->listens, '*' )) {
            //监听全部类型信息
            $result = call_user_func( $callable );
        } elseif (isset( $this->listens[$this->msgData['on']] )) {
            $result = call_user_func( $this->listens[$this->msgData['on']] );
        } else {
            exit( 'success' );
        }
        if (is_bool( $result )) { //如果匿名函数返回的是bool数据，不做处理
            exit( 'success' );
        }
        $this->push( $result );
    }


    function getData()
    {
        if (!empty( $this->msgData )) {
            return $this->msgData;
        }
        if ($_SERVER['REQUEST_METHOD'] == "POST") {
            $data = file_get_contents( "php://input" );
            if (!empty( $data )) {
                $tmp = $this->parseXML( $data );
                // 如果公众号使用加密模式
                if (isset( $tmp['Encrypt'] ) && $this->typeEncrypt == 'aes') {
                    $tmp = $this->parseXML( ( new Crypt( parent::$config ) )->deCrypt( $tmp['Encrypt'] ) );
                }
                $tmp['on'] = $tmp['MsgType'];
                if (isset( $tmp['Event'] )) {
                    $tmp['on'] .= ":{$tmp[ 'Event' ]}";
                }
                if (isset( $tmp['EventKey'] )) {
                    $tmp['on'] .= ":{$tmp[ 'EventKey' ]}";
                }
                $this->msgData = $tmp;
            }
        } elseif (isset( $_GET["echostr"] )) {
            # 微信服务器检验接口
            if ($this->check()) {
                echo $_GET["echostr"];
            }
            exit;
        }

        return $this;

    }

    private function signature( array $tmp )
    {
        sort( $tmp, SORT_STRING );
        return sha1( implode( '', $tmp ) );
    }

    private function check()
    {
        $signature = isset( $_GET['signature'] ) ? $_GET['signature'] : false;
        if (!$signature) {
            return false;
        }
        $timestamp = isset( $_GET['timestamp'] ) ? $_GET["timestamp"] : '';
        $nonce = isset( $_GET['nonce'] ) ? $_GET['nonce'] : '';
        return ( $signature == $this->signature( [$this->token, $timestamp, $nonce] ) );
    }

    function getMPid()
    {
        if (empty( $this->msgData['ToUserName'] )) {
            throw new Exception( '无效的微信公众号ID' );
        }
        return $this->msgData['ToUserName'];
    }

    function getOpenId()
    {
        if (empty( $this->msgData['FromUserName'] )) {
            throw new Exception( '无效的接收微信帐号ID' );
        }
        return $this->msgData['FromUserName'];
    }

    private function getBaseData( $type )
    {
        return array(
            'ToUserName' => $this->getOpenId(),
            'FromUserName' => $this->getMPid(),
            'CreateTime' => time(),
            'MsgType' => $type
        );
    }


    /**
     * 回复文本信息
     * @param string $content
     * @return string XML格式文本
     */
    function responseText( $content = 'ok' )
    {
        $base = $this->getBaseData( 'text' );
        $base['Content'] = $content;
        return $this->makeXML( $base );
    }

    /**
     * 将接收到的信息转发给客服，前提必须有客服在线
     * 可用有KfManager 类查询是否有客服在线
     * @param string $to_KfAccount 转发到指定客服账号
     * @return string
     */
    function transferKf( $to_KfAccount = '' )
    {
        $base = $this->getBaseData( 'transfer_customer_service' );
        if ($to_KfAccount) {
            $base += array(
                'TransInfo' => array('KfAccount' => $to_KfAccount)
            );
        }
        return $this->makeXML( $base );
    }

    function push( $data )
    {
        if ($this->typeEncrypt == 'aes') {
            $crypt = new Crypt( parent::$config );
            $enCrypt = $crypt->enCrypt( $data );
            $nonce = $crypt->randStr();
            $sign = $this->signature( array($this->token, $_SERVER['REQUEST_TIME'], $nonce, $enCrypt) );
            $data = $this->makeXML( array(
                'Encrypt' => $enCrypt,
                'MsgSignature' => $sign,
                'TimeStamp' => $_SERVER['REQUEST_TIME'],
                'Nonce' => $nonce
            ) );
        }
        echo $data;
    }

}